#!/usr/bin/env python
#coding=utf-8
from flask import Module, session, render_template, g, request, redirect, url_for, abort, flash
from functools import wraps
from happypress.forms import *
from happypress.models import *
from happypress import config
from happypress.utils.pagination import Paginator

from hanzi2pinyin import hanzi2pinyin
import hashlib, json, urllib, re, os

admin = Module(__name__,url_prefix="/admin")

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not session.get('logged',''):
            return redirect(url_for('login', next=request.url))
        return f(*args, **kwargs)
    return decorated_function

def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not (session.get('logged','') and session['user'].get('is_superuser','')):
            return redirect(url_for('login', next=request.url))
        return f(*args, **kwargs)
    return decorated_function

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in config.ALLOWED_EXTENSIONS

def allowed_size(size):
    return True if size<=config.MAX_CONTENT_LENGTH else False

def slugify(text, delim=u'-'):
    """Generates an ASCII-only slug."""
    result = []
    slug_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
    for word in slug_re.split(text.lower()):
        if word:
            result.append(word)
    return unicode(delim.join(result))

def valid_datetime(datetime):
    """
    >>> valid_datetime('2010-02-28')
    True
    >>> valid_datetime('2010-02-29')
    False    
    """
    r = re.compile(r"^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))?$")
    p = r.match(datetime)
    valid = True if p else False
    return valid

@admin.route('/')
def index():
    return redirect(url_for('dashboard'))

@admin.route('/dashboard')
@login_required
def dashboard():
    d = {}
    return render_template('admin/dashboard.html',**d)

@admin.route('/uploads', methods=['GET','POST'])
@login_required
def upload_manage():
    d = {}
    uploads = db.session.query(Upload).order_by('upload_time desc')
    d['uploads'] = uploads
    return render_template('admin/upload.html',**d)

@admin.route('/entry', methods=['GET','POST'])
@admin.route('/entry/page/<int:page>', methods=['GET','POST'])
@login_required
def entry(page=1):
    d = {}
    if page < 1:page = 1
    # filter
    entries = db.session.query(Entry).order_by('pub_date desc')
    if not session['user']['is_superuser']:
        entries = entries.filter(Entry).filter(Entry.author_id==session['user']['id'])
    category = request.args.get('category', '')
    if category and category.isdigit():
        entries = entries.filter(Entry.categories.any(Category.id==int(category)))
    status = request.args.get('status','')
    if status:
        entries = entries.filter(Entry.status==status)
    start_date = request.args.get('start_date', '')
    if start_date and valid_datetime(start_date):
        entries = entries.filter(Entry.pub_date>=start_date)
    end_date = request.args.get('end_date', '')
    if end_date and valid_datetime(end_date):
        entries = entries.filter(Entry.pub_date<=end_date)
    q = request.args.get('q', '')
    if q:
        entries = entries.filter(Entry.title.like('%'+q+'%'))
    # post here
    if request.method == 'POST':
        e_ids = [int(i) for i in request.form.getlist('e_id') if i.isdigit()]
        if e_ids:
            for i in db.session.query(Entry).filter(Entry.id.in_(e_ids)):
                i.status = 'draft'
        db.session.commit()
    # page
    paginator = Paginator(entries, config.PAGE_SIZE)
    p = paginator.page(page)
    d['p'] = p
    d['args'] = request.args
    d['categories'] = db.session.query(Category).order_by('sort_order')
    return render_template('admin/entry.html',**d)

@admin.route('/upload', methods=['POST'])
@login_required
def upload():
    if request.method == 'POST':
        #判断上传模式
        if request.environ.get('HTTP_CONTENT_DISPOSITION',''):
            info = re.search(r'name="(.+?)";\s+filename="(.+?)"',request.environ['HTTP_CONTENT_DISPOSITION'])
            if info:
                filename = info.group(2)
                f = request.data
                if not allowed_size(len(f)):
                    return json.dumps({'err':u'文件超出可上传大小','msg':''})
                try:
                    fout = open(os.path.join(config.UPLOAD_FOLDER, filename.decode('utf-8')),'wb')
                    fout.write(f)
                    fout.close()
                    f_url = '%s/%s' % (config.UPLOAD_ROOT,filename)
                except:
                    return json.dumps({'err':u'保存文件失败','msg':''})
            else:
                return json.dumps({'err':u'HTML5上传模式出错','msg':''})
        else:
            f = request.files['filedata']
            if f:
                file = f.read()
                if not allowed_size(len(file)):
                    return json.dumps({'err':u'文件超出可上传大小','msg':''})
                try:
                    f.save(os.path.join(config.UPLOAD_FOLDER, f.filename))
                except:
                    return json.dumps({'err':u'保存文件失败','msg':''})
                f_url = '%s/%s' % (config.UPLOAD_ROOT,urllib.quote(f.filename.encode('gbk')))
            else:
                return json.dumps({'err':u'请选择一个文件','msg':''})
        new = Upload(
            user_id = session['user']['id'],
            fileurl = f_url
        )
        db.session.add(new)
        try:
            db.session.commit()
            return json.dumps({'err':'','msg':f_url})
        except:
            db.session.rollback()
            return json.dumps({'err':u'插入数据库失败','msg':f_url})

@admin.route('/entry/post',methods=['GET','POST'])
@login_required
def entry_post():
    d = {}
    form = postForm(request.form)    
    if request.method == 'POST' and form.validate():
        new = Entry(
            title = form.title.data,
            slug = form.slug.data,
            excerpt = form.excerpt.data,
            body = form.body.data,
            author_id = session['user']['id'],
            enable_comments = form.enable_comments.data,
            featured = form.featured.data,
            status = 'draft' if request.form.get('draft','') else 'live'
        )
        new.categories = db.session.query(Category).filter(Category.id.in_(form.categories.raw_data)).all()
        db.session.add(new)
        try:
            db.session.commit()
            flash(u'成功发布1篇文章')
        except:
            db.session.rollback()
            flash(u'发布文章失败')
        return redirect(url_for('category'))
    d['form'] = form
    return render_template('admin/entry_post.html',**d)

@admin.route('/entry/<int:id>/edit',methods=['GET','POST'])
@login_required
def entry_edit(id):
    d = {}
    item = db.session.query(Entry).filter(Entry.id==id).first()
    if not item:
        abort(404)
    form = postForm(request.form,item)
    if request.method == 'POST' and form.validate():
        form.populate_obj(item)
        item.status = 'draft' if request.form.get('draft','') else 'live'
        try:
            db.session.commit()
            flash(u'修改成功')
        except:
            db.session.rollback()
            flash(u'操作失败')
        return redirect(url_for('category'))
    d['form'] = form
    return render_template('admin/entry_edit.html',**d)

@admin.route('/entry/<int:id>/del')
@login_required
def entry_del(id):
    item = db.session.query(Entry).filter(Entry.id==id).first()
    if item.author_id==session['user']['id'] or session['user']['is_superuser']:
        try:
            db.session.delete(item)
            db.session.commit()
            flash(u'成功删除1个文章')
        except:
            db.session.rollback()
            flash(u'操作失败')
    else:
        flash(u'没有权限删除')
    return redirect(url_for('entry'))

@admin.route('/category',methods=['GET','POST'])
@admin_required
def category():
    d = {}
    categories = db.session.query(Category).order_by('sort_order')
    if request.method == 'POST':
        for i in categories:
            sort_order = request.form.get('category_%s' % str(i.id),99,type=int)
            i.sort_order = sort_order
        try:
            db.session.commit()
            flash(u'更新成功')
        except:
            db.session.rollback()
            flash(u'更新失败')
    d['categories'] = categories
    d['no_category_entry'] = db.session.query(Entry).filter(Entry.categories==None).count()
    return render_template('admin/category.html',**d)

@admin.route('/category/add',methods=['GET','POST'])
@admin_required
def category_add():
    d = {}
    form = categoryForm(request.form)
    if request.method == 'POST' and form.validate():
        new = Category(
            title = form.title.data,
            slug = form.slug.data,
            sort_order = form.sort_order.data
        )
        db.session.add(new)
        try:
            db.session.commit()
            flash(u'添加成功')
        except:
            db.session.rollback()
            flash(u'添加失败')
        return redirect(url_for('category'))
    d['form'] = form
    return render_template('admin/category_add.html',**d)

@admin.route('/category/<int:id>/edit',methods=['GET','POST'])
@admin_required
def category_edit(id):
    d = {}
    item = db.session.query(Category).filter(Category.id==id).first()
    if not item:
        abort(404)
    form = categoryForm(request.form, item)
    if request.method == 'POST' and form.validate():
        form.populate_obj(item)
        try:
            db.session.commit()
            flash(u'修改成功')
        except:
            db.session.rollback()
            flash(u'操作失败')
        return redirect(url_for('category'))
    d['form'] = form
    return render_template('admin/category_edit.html',**d)

@admin.route('/category/<int:id>/del')
@admin_required
def category_del(id):
    c = db.session.query(Category).filter(Category.id==id).first()
    try:
        db.session.delete(c)
        db.session.commit()
        flash(u'成功删除1个分类')
    except:
        db.session.rollback()
        flash(u'操作失败')
    return redirect(url_for('category'))

@admin.route('/slug',methods=['GET'])
def slug():
    if not request.is_xhr:
        abort(404)
    keyword = request.args.get('q', '')
    fun = request.args.get('fun', '')
    slug = hanzi2pinyin(keyword)
    if fun=='translate':
        params = urllib.urlencode({'q':keyword.encode('utf-8'),'v':1.0,'langpair':'zh|en'})
        source = urllib.urlopen('http://ajax.googleapis.com/ajax/services/language/translate?%s' % params).read()
        source = json.loads(source)
        slug = source['responseData']['translatedText']
    else:
        slug = hanzi2pinyin(keyword)
    try:
        slug = slugify(slug)
    except:
        pass
    return json.dumps(slug)

@admin.route('/login',methods=['GET','POST'])
def login():
    d = {'errors':''}
    next_url = request.args.get('next', '')
    form = loginForm(request.form)
    if request.method == 'POST' and form.validate():
        if valid_login(request.form['email'],request.form['password']):
            flash(u'登录成功')
            if next_url:
                return redirect(next_url)
            return redirect(url_for('dashboard'))
        else:
            d['errors'] = u'错误的用户名或密码'
    d['form'] = form
    return render_template('admin/login.html',**d)

def valid_login(email,password):
    """This function is valid login,
    if checked auth to reg session and return True
    """
    user = check_auth(email,password)
    if user:
        session['user'] = {'id':user.id,'username':user.username,'is_superuser':user.is_superuser}
        session['logged'] = True
        return True
    else:
        return False

def check_auth(email, password):
    """This function is called to check if a email password combination is valid.
    return user sqlachemy object
    """
    md5 = hashlib.md5()
    md5.update(password)
    password_md5 = md5.hexdigest()
    user = db.session.query(User).filter(User.email==email).filter(User.password==password_md5).first()
    return user


@admin.route('/logout')
def logout():
    """ This is logout, del session"""
    session['user'] = {'username':'Anonymous'}
    session['logged'] = False
    return redirect(url_for('frontend.index'))